package com.simple.json.clazz;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;

import com.simple.json.Util;

public class FieldCache {

	private static FieldCache cache;
	private HashMap<Class<?>, ClassFieldCache> fieldCacheMap = new HashMap<Class<?>, ClassFieldCache>();

	private FieldCache() {

	}

	public static FieldCache getInstance() {
		if (cache == null) {
			synchronized (FieldCache.class) {
				if (cache == null) {
					cache = new FieldCache();
				}
			}
		}
		return cache;
	}

	/**
	 * 根据类名获取类中所有缓存的成员变量
	 * 
	 * @param clazz
	 *            类名
	 * @return
	 */
	public Collection<Field> getAllCacheFields(Class<?> clazz) {
		ClassFieldCache cached = hitOrCreateCache(clazz);
		return cached.getAllCacheFields();
	}

	/**
	 * 通过类中的成员变量名来获取field
	 * 
	 * @param clazz
	 *            类的类型
	 * @param fieldName
	 *            成员变量名
	 * @return
	 */
	public <T> Field getCache(Class<T> clazz, String fieldName) {
		ClassFieldCache cached = hitOrCreateCache(clazz);
		return cached.getCache(fieldName);
	}

	/**
	 * 获取成员变量的个数
	 * 
	 * @param clazz
	 *            类的类型
	 * @return
	 */
	public int getFieldsNum(Class<?> clazz) {
		ClassFieldCache cached = hitOrCreateCache(clazz);
		return cached.getFieldsNum();
	}

	private ClassFieldCache hitOrCreateCache(Class<?> clazz) {
		ClassFieldCache cached = fieldCacheMap.get(clazz);
		if (cached == null) {
			Util.logout("NEW Cache class = " + clazz.getName());
			cached = new ClassFieldCache(clazz);
			fieldCacheMap.put(clazz, cached);
		}

		Util.logout("HIT Cache class = " + clazz.getName());
		return cached;
	}

	private static class ClassFieldCache {
		private Class<?> cacheClazz;
		private HashMap<String, Field> fieldCacheMap = new HashMap<String, Field>();
		private int length = 0;

		public ClassFieldCache(Class<?> clazz) {
			if (clazz == null)
				throw new IllegalArgumentException("clazz should not be null");

			cacheClazz = clazz;
			cacheClassField();
		}

		private void cacheClassField() {
			// 获取类的成员变量，并缓存
			Field[] fields = cacheClazz.getDeclaredFields();
			this.length = fields.length;
			for (int i = 0; i < this.length; i++) {
				fields[i].setAccessible(true);
				fieldCacheMap.put(fields[i].getName(), fields[i]);
			}
		}

		/**
		 * 通过类中的成员变量名来获取field
		 * 
		 * @param fieldName
		 * @return
		 */
		public Field getCache(String fieldName) {
			return fieldCacheMap.get(fieldName);
		}

		/**
		 * 获取类中所有缓存的成员变量
		 * 
		 * @return
		 */
		public Collection<Field> getAllCacheFields() {
			return fieldCacheMap.values();
		}

		/**
		 * 获取成员变量的个数
		 * 
		 * @return 成员变量的个数
		 */
		public int getFieldsNum() {
			return length;
		}
	}

}
